/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.document.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.document.*;
import com.je.common.base.exception.PlatformException;
import com.je.common.base.exception.PlatformExceptionEnum;
import com.je.common.base.result.BaseRespResult;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaService;
import com.je.common.base.util.*;
import com.je.document.constants.DigestEnum;
import com.je.document.constants.LogTypeEnum;
import com.je.document.entity.DocumentBucketDO;
import com.je.document.entity.DocumentFileDO;
import com.je.document.entity.DocumentMetadataDO;
import com.je.document.entity.DocumentRelDO;
import com.je.document.exception.DocumentException;
import com.je.document.exception.DocumentExceptionEnum;
import com.je.document.model.Bucket;
import com.je.document.model.FileBO;
import com.je.document.model.FileUpload;
import com.je.document.reflection.BeanMappingHelper;
import com.je.document.service.DocumentBusService;
import com.je.document.service.FileAutoGenerator;
import com.je.document.service.FileOperateFactory;
import com.je.document.service.bucket.BucketService;
import com.je.document.service.file.FileMetaDataService;
import com.je.document.service.file.FileRelService;
import com.je.document.service.file.FileRelVersionServce;
import com.je.document.service.file.FileService;
import com.je.document.service.office.OfficePreviewServiceFactory;
import com.je.document.util.DocumentUtil;
import com.je.document.util.TxtUtil;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.ibatis.extension.plugins.pagination.Page;
import com.je.meta.rpc.setting.MetaSystemSettingRpcService;
import com.je.servicecomb.InputstreamContentTypePart;
import org.apache.commons.collections.Bag;
import org.apache.commons.collections.bag.HashBag;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 附件操作service
 *
 * @author wangmm@ketr.com.cn
 * @date 2019/8/27
 */
@Service
public class DocumentBusServiceImpl implements DocumentBusService {

    private final Logger log = LoggerFactory.getLogger(getClass());

    //缓存时间
    private static final long Cache_Time = 1000 * 60 * 60 * 24 * 30;
    @Autowired
    private MetaService metaService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private BucketService bucketService;
    @Autowired
    private FileService fileManager;
    @Autowired
    private FileAutoGenerator fileAutoGenerator;
    @Autowired
    private FileRelService fileRelService;
    @Autowired
    private FileRelVersionServce fileRelVersionServce;
    @Autowired
    private FileMetaDataService fileMetaDataService;
    @Autowired
    private MetaSystemSettingRpcService metaSystemSettingRpcService;

    @Override
    @Transactional
    public ResponseEntity<Part> previewAndDownload(HttpServletRequest request, String fileKeyPath, String fileKeyParam) {
        //用户ID
        String userId = SecurityUserHolder.getCurrentAccountRealUser() == null ? "" : SecurityUserHolder.getCurrentAccountRealUser().getId();
        //参数验证
        String fileKey = fileKeyPath;
        if (StringUtils.isBlank(fileKey)) {
            fileKey = fileKeyParam;
        }
        if (StringUtils.isBlank(fileKey)) {
            throw new DocumentException("参数错误", DocumentExceptionEnum.DOCUMENT_ERROR);
        }
        //请求路径
        String uri = request.getRequestURI();
        //获取文件信息
        FileBO fileBO;
        if (uri.contains("/preview")) {
            //查询缓存时间
            String modified = request.getHeader("If-Modified-Since");
            if (StringUtils.isNotBlank(modified) && String.valueOf(System.currentTimeMillis()).compareTo(modified) > 0) {
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
            }
            fileBO = previewFile(fileKey, userId);
        } else {
            System.out.println("文件下载开始");
            fileBO = downloadFile(fileKey, userId);
            System.out.println("获取的流");
        }

        if (fileBO == null) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }

        String fileName;
        try {
            fileName = URLEncoder.encode(fileBO.getRelName(), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error("文件名转换错误！", e);
            fileName = "未知文件.txt";
        }

        ResponseEntity.BodyBuilder bodyBuilder = ResponseEntity.ok();
        if (uri.contains("/preview")) {
            bodyBuilder.header(HttpHeaders.CONTENT_DISPOSITION, "inline;filename=" + fileName);
        } else {
            bodyBuilder.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);
        }
        return bodyBuilder.body(new InputstreamContentTypePart(fileName, fileBO.getFile(), fileBO.getContentType()));
    }


    @Override
    @Transactional
    public BaseRespResult<String> previewTxt(String fileKeyPath, String fileKeyParam) {
        try {
            //用户ID
            String userId = SecurityUserHolder.getCurrentAccountRealUser().getId();
            //参数验证
            String fileKey = fileKeyPath;
            if (StringUtils.isBlank(fileKey)) {
                fileKey = fileKeyParam;
            }
            if (StringUtils.isBlank(fileKey)) {
                throw new DocumentException("参数错误", DocumentExceptionEnum.DOCUMENT_ERROR);
            }
            //文件对象
            FileBO fileBO = previewFile(fileKey, userId);
            //读取文本内容
            String content = TxtUtil.inputStream2String(fileBO.getFile());
            IoUtil.close(fileBO.getFile());
            return BaseRespResult.successResult(content);
        } catch (Exception e) {
            if (e instanceof DocumentException) {
                throw (DocumentException) e;
            } else {
                throw new DocumentException("附件查询错误", DocumentExceptionEnum.DOCUMENT_ERROR, e);
            }
        }
    }

    @Override
    @Transactional
    public ResponseEntity<InputStream> thumbnail(HttpServletRequest request, String fileKeyPath, String fileKeyParam) {
        try {
            //参数验证
            String fileKey = fileKeyPath;
            if (StringUtils.isBlank(fileKey)) {
                fileKey = fileKeyParam;
            }
            if (StringUtils.isBlank(fileKey)) {
                throw new DocumentException("参数错误", DocumentExceptionEnum.DOCUMENT_ERROR);
            }
            //查询缓存时间
            String modified = request.getHeader("If-Modified-Since");
            if (StringUtils.isNotBlank(modified) && String.valueOf(System.currentTimeMillis()).compareTo(modified) > 0) {
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
            }
            InputStream inputStream = thumbnail(fileKey);
            if (inputStream == null) {
                throw new DocumentException("未保存缩略图", DocumentExceptionEnum.DOCUMENT_ERROR);
            }
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, ContentTypeSuffixEnum.S_png.getContentType())
                    .header(HttpHeaders.LAST_MODIFIED, String.valueOf(System.currentTimeMillis() + Cache_Time))
                    .header(HttpHeaders.EXPIRES, String.valueOf(System.currentTimeMillis() + Cache_Time))
                    .body(inputStream);
        } catch (DocumentException e) {
            throw e;
        } catch (Exception e) {
            throw new DocumentException("缩略图获取失败", DocumentExceptionEnum.DOCUMENT_ERROR, e);
        }

    }

    @Override
    public List<FileBO> saveFile(List<FileUpload> fileUploadFiles, String userId, JSONObject metadata, String bucket, String dir) {

        if (Strings.isNullOrEmpty(bucket)) {
            DynaBean bucketBean = metaService.selectOne("JE_DOCUMENT_BUCKET", ConditionsWrapper.builder().eq("is_default_bucket", "1"));
            bucket = bucketBean.getStr("bucket");
        }

        //当前时间
        Calendar now = Calendar.getInstance();

        //初始化返回值集合
        List<FileBO> files = new ArrayList<>();
        //遍历文件业务对象集合
        for (FileUpload fileUpload : fileUploadFiles) {

            //查看是否预设置key
            String fileKey = fileUpload.getFileKey();
            if (StringUtils.isNotBlank(fileKey)) {
                //如果文件存在 不执行上传逻辑
                if (selectFileByKey(fileKey) != null) {
                    continue;
                }
            } else {
                //文件唯一key
                fileKey = JEUUID.uuid();
            }

            log.warn("{} Upload file start ...", fileKey);

            //获取文件信息
            String fileName = fileUpload.getFileName();
            Long size = fileUpload.getSize();
            String contentType = fileUpload.getContentType();
            log.warn("{} File msg: name({}),size({}),type({}),bucket({}).", fileKey, fileName, size, contentType, bucket);

            //获取上传文件数据
            log.warn("{} Start read byte array ...", fileKey);
            long currentTimeMillis = System.currentTimeMillis();
            byte[] bytes = IoUtil.readBytes(fileUpload.getFile());
            log.warn("{} Read byte success, cost time: {}.", fileKey, System.currentTimeMillis() - currentTimeMillis);

            try {
                //存储空间
                Bucket bucketBO = fileManager.findBucket(bucket);
                //相同文件
                DynaBean fileDO = null;
                DigestEnum digestEnum = null;
                String digestValue = null;

                //如果是指定存储路径 不做唯一校验
                if (StringUtils.isBlank(dir) && fileAutoGenerator.checkDigest()) {
                    //获取默认摘要类型
                    digestEnum = DigestEnum.getDefault();
                    //获取文件摘要信息
                    digestValue = fileManager.messageDigest(bytes, digestEnum);

                    log.warn("{} Check file digest.", fileKey);
                    //根据摘要查找文件是否已存在
                    fileDO = fileManager.selectFileByDigestBucket(digestEnum.getCode(), digestValue, bucketBO.getBucket());
                    //验证文件是否已经被删除
                    if (fileDO != null && !fileManager.existFile(fileDO.getStr("file_path"), fileDO.getStr("bucket"))) {
                        fileDO.set("IS_DELETED", 1);
                        //物理删除文件信息
                        fileRelService.deleteFileByFileId(Collections.singletonList(fileDO.getStr("je_document_file_id")));
                        fileDO = null;
                    }
                }

                if (fileDO == null) {
                    //上传文件
                    currentTimeMillis = System.currentTimeMillis();
                    log.warn("{} Save file start ...", fileKey);
                    FileSaveDTO fileSaveDTO = fileManager.saveFile(fileName, contentType, bytes, bucketBO, dir);
                    log.warn("{} Save file success, cost time: {}.", fileKey, System.currentTimeMillis() - currentTimeMillis);

                    //文件基础信息DO
                    fileDO = new DynaBean("JE_DOCUMENT_FILE", false);
                    //copy属性:name suffix fullName filePath fullUrl bucket saveType permission thumbnail
                    fileDO.set("name", fileName.substring(0, fileName.lastIndexOf(".")));
                    fileDO.set("full_name", fileName);
                    fileDO.set("bucket", bucketBO.getBucket());
                    fileDO.set("thumbnail", fileSaveDTO.getThumbnail());
                    fileDO.set("save_type", bucketBO.getSaveType());
                    fileDO.set("suffix", fileSaveDTO.getSuffix());
                    fileDO.set("file_path", fileSaveDTO.getFilePath());
                    fileDO.set("permission", bucketBO.getPermission());
                    fileDO.set("full_url", fileSaveDTO.getFullUrl());
                    fileDO.set("create_user", userId);
                    fileDO.set("modified_user", userId);
                    fileDO.set("version", 1);
                    //文件目录
                    String[] splitFolder = fileSaveDTO.getFilePath().split("/");
                    fileDO.set("FILE_FOLDER", fileSaveDTO.getFilePath().replaceAll(splitFolder[splitFolder.length - 1], ""));
                    //文件信息
                    fileDO.set("content_type", fileUpload.getContentType());
                    fileDO.set("FILE_SIZE", fileUpload.getSize());
                    //摘要信息,指定存储目录不记录摘要
                    if (StringUtils.isBlank(dir) && fileAutoGenerator.checkDigest()) {
                        fileDO.set("digest_type", digestEnum.getCode());
                        fileDO.set("digest_value", digestValue);
                    }
                    //人员信息
                    fileDO.set("create_user", userId);
                    fileDO.set("create_time", DateUtils.formatDateTime(new Date()));
                    fileDO.set("modified_user", userId);
                    fileDO.set("is_deleted", "0");
                    //保存文件信息
                    metaService.insert(fileDO);
                }

                //业务关联信息DO
                DynaBean relDO = new DynaBean("JE_DOCUMENT_REL", false);
                relDO.set("file_id", fileDO.getStr("je_document_file_id"));
                relDO.set("name", fileUpload.getFileName());
                relDO.set("file_key", fileKey);
                //人员信息
                relDO.set("create_user", userId);
                relDO.set("version", "0");
                relDO.set("is_deleted", "0");
                relDO.set("create_time", DateUtils.formatDateTime(new Date()));
                //保存
                commonService.buildModelCreateInfo(relDO);
                metaService.insert(relDO);

                //记录日志
                DynaBean logDO = new DynaBean("JE_DOCUMENT_LOG", false);
                logDO.set("file_id", fileDO.getStr("je_document_file_id"));
                logDO.set("rel_id", relDO.getStr("je_document_rel_id"));
                logDO.set("type", LogTypeEnum.UPLOAD.getCode());
                logDO.set("is_deleted", "0");
                //人员信息
                logDO.set("create_user", userId);
                logDO.set("create_time", DateUtils.formatDateTime(new Date()));
                //保存
                metaService.insert(logDO);

                //业务元数据保存
                if (metadata == null) {
                    metadata = new JSONObject();
                }

                //设置元数据
                metadata.put(MetadataEnum.relName.getCode(), relDO.getStr("name"));
                metadata.put(MetadataEnum.fileKey.getCode(), relDO.getStr("file_key"));

                metadata.put(MetadataEnum.suffix.getCode(), fileDO.getStr("suffix"));
                metadata.put(MetadataEnum.size.getCode(), fileDO.getInt("file_size"));
                metadata.put(MetadataEnum.bucket.getCode(), fileDO.getStr("bucket"));

                metadata.put(MetadataEnum.createUser.getCode(), userId);
                metadata.put(MetadataEnum.createTime.getCode(), DateUtil.formatDateTime(now.getTime()));
                saveFileMetadata(userId, metadata, relDO.getStr("je_document_rel_id"), fileDO.getStr("je_document_file_id"));

                //返回数据
                FileBO fileBO = new FileBO();
                DocumentFileDO documentFileDO = BeanMappingHelper.transform(fileDO.getValues(), DocumentFileDO.class);
                DocumentRelDO documentRelDO = BeanMappingHelper.transform(relDO.getValues(), DocumentRelDO.class);
                BeanUtil.copyProperties(documentFileDO, fileBO);
                BeanUtil.copyProperties(documentRelDO, fileBO);
                BeanUtil.fillBeanWithMap(metadata, fileBO, true);
                fileBO.setFileId(fileDO.getStr("je_document_file_id"));
                fileBO.setRelId(relDO.getStr("je_document_rel_id"));
                //单位为kb
                if (fileUpload.getSize() != null) {
                    fileBO.setSize(fileUpload.getSize() / 1024);
                }

                //添加结果集
                files.add(fileBO);
            } catch (DocumentException e) {
                throw e;
            } catch (RuntimeException e) {
                throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_SAVE_FAIL, e);
            }
            currentTimeMillis = System.currentTimeMillis();
            log.warn("{} Upload file end ...", fileKey);
        }
        return files;
    }

    @Override
    @Transactional
    public List<FileBO> boundFile(List<FileBound> fileBounds, String userId, JSONObject metadata, String bucket) {

        if (Strings.isNullOrEmpty(bucket)) {
            DynaBean bucketBean = metaService.selectOne("JE_DOCUMENT_BUCKET", ConditionsWrapper.builder().eq("is_default_bucket", "1"));
            bucket = bucketBean.getStr("bucket");
        }

        //当前时间
        Calendar now = Calendar.getInstance();
        //初始化返回值集合
        List<FileBO> files = new ArrayList<>();
        for (FileBound fileBound : fileBounds) {
            //查看是否预设置key
            String fileKey = fileBound.getFileKey();
            if (StringUtils.isNotBlank(fileKey)) {
                //如果文件存在 不执行上传逻辑
                if (selectFileByKey(fileKey) != null) {
                    continue;
                }
            } else {
                //文件唯一key
                fileKey = JEUUID.uuid();
            }

            log.warn("{} Bound file start ...", fileKey);

            //获取文件信息
            String fileName = fileBound.getFileName();
            Long size = fileBound.getSize();
            String contentType = fileBound.getContentType();
            log.warn("{} File msg: name({}),size({}),type({}),bucket({}).", fileKey, fileName, size, contentType, bucket);
            try {
                //存储空间
                Bucket bucketBO = fileManager.findBucket(bucket);
                //文件基础信息DO
                DynaBean fileDO = new DynaBean("JE_DOCUMENT_FILE", false);
                //set属性:name suffix fullName filePath fullUrl bucket saveType permission thumbnail

                String[] splits = fileName.split("\\.");
                String suffix = splits.length == 1 ? "" : splits[splits.length - 1];
                fileDO.set("name", fileName.substring(0, fileName.lastIndexOf(".")));
                fileDO.set("full_name", fileName);
                fileDO.set("bucket", bucket);
                fileDO.set("save_type", bucketBO.getSaveType());
                fileDO.set("suffix", suffix);
                fileDO.set("file_path", fileBound.getFolder() + File.separator + fileBound.getFileName());
                fileDO.set("permission", bucketBO.getPermission());
                fileDO.set("full_url", fileBound.getFullUrl());
                fileDO.set("folder", fileBound.getFolder());
                fileDO.set("content_type", fileBound.getContentType());
                fileDO.set("file_size", fileBound.getSize());
                fileDO.set("create_user", userId);
                fileDO.set("modified_user", userId);
                fileDO.set("is_deleted", "0");
                //保存文件信息
                metaService.insert(fileDO);
                //业务关联信息DO
                DynaBean relDO = new DynaBean("JE_DOCUMENT_REL", false);
                relDO.set("file_id", fileDO.getStr("je_document_file_id"));
                relDO.set("name", fileBound.getFileName());
                relDO.set("file_key", fileKey);
                relDO.set("create_user", userId);
                relDO.set("modified_user", userId);
                relDO.set("version", "0");
                relDO.set("is_deleted", "0");
                //保存

                metaService.insert(relDO);

                //记录日志
                DynaBean logDO = new DynaBean("JE_DOCUMENT_LOG", false);
                logDO.set("file_id", fileDO.getStr("je_document_file_id"));
                logDO.set("rel_id", relDO.getStr("je_document_rel_id"));
                logDO.set("is_deleted", "0");
                logDO.set("type", LogTypeEnum.BOUNDED.getCode());
                logDO.set("create_user", userId);
                relDO.set("create_time", DateUtils.formatDateTime(new Date()));
                //保存
                metaService.insert(logDO);

                //业务元数据保存
                if (metadata == null) {
                    metadata = new JSONObject();
                }
                //设置元数据
                metadata.put(MetadataEnum.relName.getCode(), relDO.getStr("name"));
                metadata.put(MetadataEnum.fileKey.getCode(), relDO.getStr("file_key"));

                metadata.put(MetadataEnum.suffix.getCode(), fileDO.getStr("suffix"));
                metadata.put(MetadataEnum.size.getCode(), fileDO.getInt("file_size"));
                metadata.put(MetadataEnum.bucket.getCode(), fileDO.getStr("bucket"));

                metadata.put(MetadataEnum.createUser.getCode(), userId);
                metadata.put(MetadataEnum.createTime.getCode(), DateUtil.formatDateTime(now.getTime()));
                saveFileMetadata(userId, metadata, relDO.getStr("je_document_rel_id"), fileDO.getStr("je_document_file_id"));

                //返回数据
                FileBO fileBO = new FileBO();
                DocumentFileDO documentFileDO = BeanMappingHelper.transform(fileDO.getValues(), DocumentFileDO.class);
                DocumentRelDO documentRelDO = BeanMappingHelper.transform(relDO.getValues(), DocumentRelDO.class);
                BeanUtil.copyProperties(documentFileDO, fileBO);
                BeanUtil.copyProperties(documentRelDO, fileBO);
                BeanUtil.fillBeanWithMap(metadata, fileBO, true);
                fileBO.setFileId(fileDO.getStr("je_document_file_id"));
                fileBO.setRelId(relDO.getStr("je_document_rel_id"));
                //添加结果集
                files.add(fileBO);
            } catch (DocumentException e) {
                throw e;
            } catch (RuntimeException e) {
                throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_BOUND_FAIL, e);
            }
            log.warn("{} Bound file end ...", fileKey);
        }
        return files;
    }

    @Override
    @Transactional
    public void saveFileMetadata(String userId, JSONObject metadata, List<String> fileKeys) {

        if (fileKeys == null || fileKeys.isEmpty() || metadata == null || metadata.isEmpty()) {
            return;
        }
        Set<String> fileKeySet = fileKeys.stream().collect(Collectors.toSet());
        for (String fileKey : fileKeySet) {
            //获取文件信息
            DocumentRelDO relDO = fileRelService.selectOneByKey(fileKey);
            if (relDO == null) {
                continue;
            }
            metaService.executeSql("update je_document_rel set modifiedUser={0},modifiedTime={1} where je_document_rel_id = {2}", userId, new Date(), relDO.getId());
            //调用元数据保存方法
            saveFileMetadata(userId, metadata, relDO.getId(), relDO.getFileId());
        }
    }

    @Override
    @Transactional
    public void saveFileMetadata(String userId, JSONObject metadata, String relId, String fileId) {
        try {

            if (metadata == null || metadata.isEmpty()) {
                throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_METADATA_EMPTY);
            }

            //设置更新元数据
            Date now = new Date();
            metadata.put(MetadataEnum.modifiedUser.getCode(), userId);
            metadata.put(MetadataEnum.modifiedTime.getCode(), DateUtil.formatDateTime(now));
            //记录日志信息

            //遍历元数据
            for (String code : metadata.keySet()) {
                if (Strings.isNullOrEmpty(metadata.getString(code))) {
                    continue;
                }
                //校验key
                MetadataEnum metadataEnum = MetadataEnum.getDefault(code);
                if (metadataEnum == null) {
                    continue;
                }
                //元数据内容
                String content = metadata.getString(code);
                if (metadataEnum == MetadataEnum.uploadType) {
                    content = UploadTypeEnum.getDefault(content).getCode();
                }

                //校验元数据是否存在，不存在则新增，存在则校验是否允许修改
                DynaBean metadataDO = fileMetaDataService.selectMetadataBean(relId, code);
                if (metadataDO == null) {
                    metadataDO = new DynaBean("JE_DOCUMENT_METADATA", false);
                    metadataDO.set("rel_id", relId);
                    metadataDO.set("file_id", fileId);
                    metadataDO.set("code", code);
                    metadataDO.set("content", content);
                    metadataDO.set("create_user", userId);
                    metadataDO.set("is_deleted", "0");
                    metadataDO.set("version", "0");
                    metadataDO.set("create_time", DateUtils.formatDateTime(new Date()));
                    //保存
                    metaService.insert(metadataDO);
                } else if (metadataEnum.getUpdate()) {
                    //设置更新数据
                    metadataDO.set("content", content);
                    metadataDO.set("modified_user", userId);
                    metadataDO.set("modified_time", DateUtils.formatDateTime(new Date()));
                    //更新
                    metaService.update(metadataDO);
                }
            }
        } catch (Exception e) {
            throw new DocumentException(e.getMessage(), DocumentExceptionEnum.DOCUMENT_SERVICE_METADATA_EMPTY, e);
        }
    }

    @Override
    @Transactional
    public void updateMetadataByKey(String fileKey, String newRelName, JSONObject metadata, String userId) {

        //查询文件信息
        DocumentRelDO relDO = fileRelService.selectOneByKey(fileKey);
        if (relDO == null) {
            throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_FILE_NOT_FIND);
        }

        //修改文件名
        if (StringUtils.isNotBlank(newRelName)) {
            relDO.setName(newRelName);
            relDO.setModifiedUser(userId);
            relDO.setModifiedTime(new Date());
            metaService.executeSql("update je_document_rel set name={0}, modifiedUser={1},modifiedTime={2} where je_document_rel_id = {3}",
                    newRelName, userId, DateUtils.formatDateTime(new Date()));
        }

        //获取业务关联ID
        String relId = relDO.getId();
        //获取业务文件ID
        String fileId = relDO.getFileId();

        //设置文件名
        metadata.put(MetadataEnum.relName.getCode(), relDO.getName());

        //更新修改业务元数据
        saveFileMetadata(userId, metadata, relId, fileId);

    }

    @Override
    @Transactional
    public JSONObject selectFileMetadataByKey(String fileKey) {

        JSONObject metadata = new JSONObject();
        //获取所有元数据
        List<DocumentMetadataDO> metadataDOS = fileMetaDataService.selectFileMetadata(fileKey);
        for (DocumentMetadataDO metadataDO : metadataDOS) {
            String code = metadataDO.getCode();
            String content = metadataDO.getContent();
            //放入JSON
            metadata.put(code, content);
        }
        return metadata;
    }

    @Override
    @Transactional
    public FileBO editByFileKey(String fileKey, InputStream inputStream, String userId) {
        try {
            //获取上传文件数据
            byte[] bytes = IoUtil.readBytes(inputStream);

            FileBO fileBO = selectFileByKey(fileKey);
            String bucket = fileBO.getBucket();
            String relName = fileBO.getRelName();
            String contentType = fileBO.getContentType();

            //获取默认摘要类型
            DigestEnum digestEnum = DigestEnum.getDefault();
            //获取文件摘要信息
            String digestValue = fileManager.messageDigest(bytes, digestEnum);
            Bucket bucketBO = fileManager.findBucket(bucket);

            //根据摘要查找文件是否已存在
            DynaBean fileBean = fileManager.selectFileByDigestBucket(digestEnum.getCode(), digestValue, bucketBO.getBucket());
            if (fileBean == null) {
                //上传文件
                FileSaveDTO fileSaveDTO = fileManager.saveFile(relName, contentType, bytes, bucketBO);
                //文件基础信息DO
                fileBean = new DynaBean("JE_DOCUMENT_FILE", false);

                fileBean.set("name", fileSaveDTO.getName());
                fileBean.set("full_name", fileSaveDTO.getFullName());
                fileBean.set("bucket", fileSaveDTO.getBucket());
                fileBean.set("file_path", fileSaveDTO.getFilePath());
                fileBean.set("save_type", fileSaveDTO.getSaveType());
                fileBean.set("permission", fileSaveDTO.getPermission());
                fileBean.set("full_url", fileSaveDTO.getFullUrl());
                fileBean.set("suffix", fileSaveDTO.getSuffix());
                fileBean.set("thumbnail", fileSaveDTO.getThumbnail());
                //文件目录
                String[] splitFolder = fileSaveDTO.getFilePath().split("/");
                fileBean.set("folder", fileSaveDTO.getFilePath().replaceAll(splitFolder[splitFolder.length - 1], ""));
                //文件信息
                fileBean.set("content_type", contentType);
                fileBean.set("file_size", bytes.length);

                //摘要信息
                fileBean.set("digest_type", digestEnum.getCode());
                fileBean.set("digest_value", digestEnum.getCode());

                //人员信息
                fileBean.set("create_user", userId);
                fileBean.set("create_time", DateUtils.formatDateTime(new Date()));
                fileBean.set("is_deleted", "0");
                //保存文件信息
                metaService.insert(fileBean);
            }

            //修改文件引用ID
            DocumentRelDO relDO = fileRelService.selectOneByKey(fileKey);
            DynaBean documentRelVersionBean = new DynaBean("JE_DOCUMENT_REL_VERSION", false);
            documentRelVersionBean.set("file_id", relDO.getFileId());
            documentRelVersionBean.set("rel_id", fileBO.getRelId());
            documentRelVersionBean.set("name", fileBO.getRelName());
            documentRelVersionBean.set("create_user", relDO.getCreateUser());
            documentRelVersionBean.set("modified_user", userId);
            documentRelVersionBean.set("version", relDO.getVersion());
            documentRelVersionBean.set("file_key", fileKey);
            documentRelVersionBean.set("create_time", DateUtils.formatDateTime(new Date()));
            metaService.insert(documentRelVersionBean);
            metaService.executeSql("update je_document_rel set version={0},file_id={1} where je_document_rel_id = {2}", relDO.getVersion() + 1, fileBean.getStr("je_document_file_id"), relDO.getId());

            DynaBean logBean = new DynaBean("JE_DOCUMENT_LOG", false);
            logBean.set("file_id", fileBean.getStr("je_document_file_id"));
            logBean.set("rel_id", relDO.getId());
            logBean.set("type", LogTypeEnum.UPDATE.getCode());
            logBean.set("content", "oldFileId:" + relDO.getFileId());
            logBean.set("create_user", userId);
            logBean.set("is_deleted", "0");
            logBean.set("create_time", DateUtils.formatDateTime(new Date()));
            metaService.insert(logBean);
            return selectFileByKey(fileKey);
        } catch (Exception e) {
            throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_FILE_NOT_FIND);
        }
    }

    @Override
    @Transactional
    public FileBO copyRelByKey(String fileKey, String newRelName, JSONObject metadata, String userId) {

        //查询文件信息
        DocumentRelDO oldRelDO = fileRelService.selectOneByKey(fileKey);

        if (oldRelDO == null) {
            throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_FILE_NOT_FIND);
        }

        //新文件引用对象
        DynaBean newRelBean = new DynaBean("JE_DOCUMENT_REL", false);
        newRelBean.set("name", StringUtils.isNotBlank(newRelName) ? newRelName : oldRelDO.getName());
        newRelBean.set("file_id", oldRelDO.getFileId());
        newRelBean.set("file_key", JEUUID.uuid());
        newRelBean.set("create_user", userId);
        newRelBean.set("version", oldRelDO.getVersion());
        newRelBean.set("create_time", DateUtils.formatDateTime(new Date()));
        newRelBean.set("is_deleted", "0");
        metaService.insert(newRelBean);

        //被复制文件的元数据
        JSONObject oldMetadata = selectFileMetadataByKey(oldRelDO.getFileKey());

        //合并元数据
        for (String key : metadata.keySet()) {
            oldMetadata.put(key, metadata.get(key));
        }

        //设置文件名
        metadata.put(MetadataEnum.relName.getCode(), newRelBean.getStr("name"));

        //新增业务元数据
        saveFileMetadata(userId, oldMetadata, newRelBean.getStr("je_document_rel_id"), newRelBean.getStr("file_id"));
        FileBO fileBO = selectFileByKey(newRelBean.getStr("file_key"));
        return fileBO;
    }

    @Override
    @Transactional
    public void delFilesByKey(List<String> fileKeys, String userId) {
        if (fileKeys == null || fileKeys.isEmpty()) {
            return;
        }
        //逻辑删除文件
        fileRelService.deleteFilesByKey(fileKeys, userId);
    }

    @Override
    @Transactional
    public void deleteByFileKeys(List<String> fileKeys, String userId) {
        if (fileKeys == null || fileKeys.isEmpty()) {
            return;
        }
        List<Map<String, Object>> fileInfoLists = fileRelService.selectListByKeys(fileKeys);
        List<String> fileRelIds = new ArrayList<>();
        List<Map<String, String>> fileDeleteInfos = new ArrayList<>();
        List<String> fileIds = new ArrayList<>();
        List<String> deleteFileIds = new ArrayList<>();

        if (null != fileInfoLists && fileInfoLists.size() > 0) {
            for (Map<String, Object> fileInfo : fileInfoLists) {
                fileIds.add(fileInfo.get("fileId").toString());
            }
            for (Map<String, Object> fileInfo : fileInfoLists) {
                String fileId = fileInfo.get("fileId").toString();
                //根据fileId查文件引用表，是否引用数据条数大于1，如果大于1 删除引用信息，如果等于1 删除具体文件
                List<Map<String, Object>> fileIdList = fileRelService.selectListByFileId(fileId);
                Bag bag = new HashBag(fileIds);
                int count = bag.getCount(fileId);
                if (fileIdList != null && fileIdList.size() > 0) {
                    //物理删除文件引用信息
                    fileRelIds.add(fileInfo.get("relId").toString());
                }
                if (fileIdList != null && (fileIdList.size() == 1 || count >= fileIdList.size())) {
                    deleteFileIds.add(fileId);
                    //删除具体服务器文件和文件信息
                    Map<String, String> map = new HashMap<>(3);
                    map.put("filePath", fileInfo.get("filePath").toString());
                    map.put("thumbnail", fileInfo.get("thumbnail") == null ? "" : fileInfo.get("thumbnail").toString());
                    map.put("bucket", fileInfo.get("bucket") == null ? "" : fileInfo.get("bucket").toString());
                    fileDeleteInfos.add(map);
                }
                //记录日志
                DynaBean logDO = new DynaBean("JE_DOCUMENT_LOG", false);
                logDO.set("file_id", fileInfo.get("fileId").toString());
                logDO.set("rel_id", fileInfo.get("relId").toString());
                logDO.set("type", LogTypeEnum.DEL.getCode());
                logDO.set("is_deleted", "0");
                //人员信息
                logDO.set("create_user", userId);
                logDO.set("create_time", DateUtils.formatDateTime(new Date()));
                //保存
                metaService.insert(logDO);
            }
            //物理删除文件引用信息
            fileRelService.deleteFilesByFileRelIds(fileRelIds);
            //物理删除文件元数据信息
            fileRelService.deleteMetaDataByFileRelId(fileRelIds);
            //物理删除文件信息
            fileRelService.deleteFileByFileId(deleteFileIds);
            //删除具体文件
            fileManager.deleteFilesByFileInfo(fileDeleteInfos);

        }
    }

    @Override
    @Transactional
    public boolean exists(String fileKey) {
        FileBO fileBO = selectFileByKey(fileKey);
        if (fileBO == null) {
            log.info("FileKey not find in datasource, fileKey:[{}]", fileKey);
            return false;
        }
        if (!fileManager.existFile(fileBO.getFilePath(), fileBO.getBucket())) {
            log.info("File not find in bucket, bucket:[{}], fileKey:[{}]", fileBO.getBucket(), fileKey);
            return false;
        }
        return true;
    }

    @Override
    @Transactional
    public FileBO selectFileByKey(String fileKey) {
        return selectFileByKeyAndVersion(fileKey, "");
    }

    @Override
    @Transactional
    public FileBO selectFileByKeyAndVersion(String fileKey, String version) {
        Map<String, Object> fileMap;
        if (!Strings.isNullOrEmpty(version)) {
            fileMap = fileRelService.selectRelMapByKey(fileKey, version);
        } else {
            fileMap = fileRelService.selectRelMapByKey(fileKey);
        }
        if (fileMap == null) {
            return null;
        }
        FileBO fileBO = BeanMappingHelper.transform(fileMap, FileBO.class);
        return fileBO;
    }

    @Override
    @Transactional
    public List<FileBO> selectFileListByKey(List<String> keys) {
        //文件信息
        List<FileBO> fileBOList = new ArrayList<>();
        //查询结果
        List<Map<String, Object>> fileMapList = fileRelService.selectListByKeys(keys);
        for (Map<String, Object> fileMap : fileMapList) {
            FileBO fileBO = BeanMappingHelper.transform(fileMap, FileBO.class);
            fileBOList.add(fileBO);
        }
        return fileBOList;
    }

    @Override
    @Transactional
    public List<FileBO> selectFileByMetadata(JSONObject metadataQuery) {
        if (metadataQuery == null || metadataQuery.isEmpty()) {
            throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_METADATA_EMPTY);
        }
        return BeanMappingHelper.transformList(fileRelService.selectFileMapByMetadata(metadataQuery), FileBO.class);
    }

    @Override
    @Transactional
    public List<FileBO> selectFileFullByMetadata(JSONObject metadataQuery) {
        List<FileBO> fileBOS = selectFileByMetadata(metadataQuery);
        for (FileBO fileBO : fileBOS) {
            fileBO.setFile(fileManager.readFile(fileBO.getFilePath(), fileBO.getBucket()));
            JSONObject metadata = selectFileMetadataByKey(fileBO.getFileKey());
        }
        return fileBOS;
    }

    @Override
    @Transactional
    public Page<FileBO> selectFilePageByMetadata(JSONObject metadataQuery, int start, int limit, String orderBy) {

        if (metadataQuery == null || metadataQuery.isEmpty()) {
            throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_METADATA_EMPTY);
        }
        //查询结果
        Map<String, String> metadataMap = metadataQuery.toJavaObject(HashMap.class);
        Page<Map<String, Object>> mapPage = new Page<>(start, limit);
        List<Map<String, Object>> list = fileRelService.selectFileMapPageByMetadata(mapPage, metadataMap, orderBy);
        List<FileBO> fileBOS = BeanMappingHelper.transformList(mapPage.getRecords(), FileBO.class);
        Page<FileBO> page = new Page(fileBOS);
        page.setTotal(mapPage.getTotal());
        return page;
    }

    @Override
    @Transactional
    public FileBO readFile(String fileKey) {
        return readFile(fileKey, "");
    }

    @Override
    @Transactional
    public FileBO readFile(String fileKey, String version) {
        FileBO fileBO = new FileBO();
        if (!Strings.isNullOrEmpty(version)) {
            fileBO = selectFileByKeyAndVersion(fileKey, version);
        } else {
            fileBO = selectFileByKey(fileKey);
        }
        if (fileBO != null) {
            fileBO.setFile(fileManager.readFile(fileBO.getFilePath(), fileBO.getBucket()));
        }
        return fileBO;
    }

    @Override
    @Transactional
    public FileBO previewFile(String fileKey, String userId) {
        return previewFile(fileKey, userId, "");
    }

    @Override
    @Transactional
    public FileBO previewFile(String fileKey, String userId, String version) {
        FileBO fileBO = new FileBO();
        if (Strings.isNullOrEmpty(version)) {
            fileBO = readFile(fileKey);
        } else {
            fileBO = readFile(fileKey, version);
        }
        if (fileBO == null) {
            return null;
        }
        if (StringUtil.isNotEmpty(userId)) {
            DynaBean logBean = new DynaBean("JE_DOCUMENT_LOG", false);
            logBean.set("file_id", fileBO.getFileId());
            logBean.set("rel_id", fileBO.getRelId());
            logBean.set("type", LogTypeEnum.PREVIEW.getCode());
            logBean.set("create_user", userId);
            logBean.set("is_deleted", "0");
            logBean.set("create_time", DateUtils.formatDateTime(new Date()));
            metaService.insert(logBean);
        }
        return fileBO;
    }

    @Override
    @Transactional
    public FileBO downloadFile(String fileKey, String userId) {
        return downloadFile(fileKey, userId, "");
    }

    @Override
    @Transactional
    public FileBO downloadFile(String fileKey, String userId, String version) {
        FileBO fileBO = new FileBO();
        if (!Strings.isNullOrEmpty(version)) {
            fileBO = readFile(fileKey, version);
        } else {
            fileBO = readFile(fileKey);
        }
        if (fileBO == null) {
            return null;
        }
        DynaBean logBean = new DynaBean("JE_DOCUMENT_LOG", false);
        logBean.set("file_id", fileBO.getFileId());
        logBean.set("rel_id", fileBO.getRelId());
        logBean.set("type", LogTypeEnum.DOWNLOAD.getCode());
        logBean.set("create_user", userId);
        logBean.set("is_deleted", "0");
        logBean.set("create_time", DateUtils.formatDateTime(new Date()));
        metaService.insert(logBean);

        return fileBO;
    }

    @Override
    @Transactional
    public InputStream thumbnail(String fileKey) {
        FileBO fileBO = selectFileByKey(fileKey);
        if (fileBO == null) {
            return null;
        }
        if (StringUtils.isNotBlank(fileBO.getThumbnail())) {
            return fileManager.readFile(fileBO.getThumbnail(), fileBO.getBucket());
        } else {
            //生成缩略图，兼容老数据无缩略图
            InputStream inputStream = fileManager.readFile(fileBO.getFilePath(), fileBO.getBucket());
            byte[] bytes = IoUtil.readBytes(inputStream);
            IoUtil.close(inputStream);
            fileBO.setContentType("image/png");
            return fileManager.thumbnail(fileBO.getBucket(), bytes, fileBO.getContentType(), fileBO.getSuffix(), "");
        }
    }

    @Override
    public InputStream buildZip(List<String> fileKeys) {
        //文件信息
        List<FileBO> fileBOList = selectFileListByKey(fileKeys);
        if (fileBOList.size() == 0) {
            throw new DocumentException(DocumentExceptionEnum.DOCUMENT_SERVICE_FILE_NOT_FIND);
        }
        //文件名称
        List<String> relNameList = new ArrayList<>();
        //文件存储路径
        List<String> filePathList = new ArrayList<>();
        //文件存储空间
        List<String> bucketList = new ArrayList<>();
        for (FileBO fileBO : fileBOList) {
            relNameList.add(fileBO.getRelName());
            filePathList.add(fileBO.getFilePath());
            bucketList.add(fileBO.getBucket());
        }

        return fileManager.buildZip(relNameList, filePathList, bucketList);
    }

    @Override
    public List<FileBO> selectAllVersionFiles(String fikeKey) {
        //文件信息
        List<FileBO> fileBOList = new ArrayList<>();
        //查询结果
        List<Map<String, Object>> fileMapList = fileRelVersionServce.selectAllVersionFiles(fikeKey);
        for (Map<String, Object> fileMap : fileMapList) {
            FileBO fileBO = BeanMappingHelper.transform(fileMap, FileBO.class);
            fileBOList.add(fileBO);
        }
        return fileBOList;
    }

    @Override
    public FileBO selectVersionFile(String fikeKey, int version) {
        //查询结果
        Map<String, Object> fileMap = fileRelVersionServce.selectVersionFile(fikeKey, version);
        FileBO fileBO = BeanMappingHelper.transform(fileMap, FileBO.class);
        return fileBO;
    }

    @Override
    @Transactional
    public void updateFiledFile(String userId, String tableCode, String pkValue, String fieldCode, List<String> usedFileKey) {

        //根据 tableCode pkValue filedCode 查找字段中的附件
        JSONObject metadataObject = new JSONObject();
        metadataObject.put(MetadataEnum.tableCode.getCode(), tableCode);
        metadataObject.put(MetadataEnum.pkValue.getCode(), pkValue);
        metadataObject.put(MetadataEnum.fieldCode.getCode(), fieldCode);
        //查找已有附件
        List<DocumentRelDO> relDOS = fileRelService.selectRelByMetadata(metadataObject);

        //使用到的文件业务关联数据ID
        List<String> usedRelIds = new ArrayList<>();

        //逻辑删除没有被引用的附件
        for (DocumentRelDO relDO : relDOS) {
            //文件唯一标识
            String fileKey = relDO.getFileKey();
            if (usedFileKey != null && !usedFileKey.contains(fileKey)) {
                //逻辑删除
                metaService.executeSql("update je_document_rel set modified_user={0},modified_time={1},is_deleted=1", userId, DateUtils.formatDateTime(new Date()));
            } else {
                usedRelIds.add(relDO.getId());
            }
        }

        //将使用到的文件业务关联数据 UploadType TEMP改为FORM UploadTypeEnum
        if (!usedRelIds.isEmpty()) {
            fileMetaDataService.updateTempToForm(usedRelIds, userId);
        }

        //启用文件 is_deleted = 0
        fileRelService.useFilesByKey(usedFileKey, userId);
    }

    @Override
    @Transactional
    public List<FileCopyDTO> copyFiles(String userId, String tableCode, String pkValue, String fieldCode, String newPkValue, String newFuncCode, String newTableCode, String newFiledCode) {

        List<FileCopyDTO> newCopyFiles = new ArrayList<>();
        //拼接查询条件
        JSONObject metadataJSON = new JSONObject();
        metadataJSON.put(MetadataEnum.tableCode.getCode(), tableCode);
        metadataJSON.put(MetadataEnum.pkValue.getCode(), pkValue);
        metadataJSON.put(MetadataEnum.fieldCode.getCode(), fieldCode);
        //查询
        List<DocumentRelDO> rels = fileRelService.selectRelByMetadata(metadataJSON);
        DynaBean eachRelBean;
        for (DocumentRelDO rel : rels) {

            //记录业务关联表ID
            String oldRelId = rel.getId();
            String fileId = rel.getFileId();

            eachRelBean = new DynaBean("JE_DOCUMENT_REL", false);
            eachRelBean.set("file_id", rel.getId());
            eachRelBean.set("name", rel.getName());
            eachRelBean.set("file_key", JEUUID.uuid());
            eachRelBean.set("version", "0");
            eachRelBean.set("is_deleted", "0");
            eachRelBean.set("create_time", DateUtils.formatDateTime(new Date()));
            eachRelBean.set("create_user", userId);
            metaService.insert(eachRelBean);

            //获取新插入记录的ID
            String newRelId = eachRelBean.getStr("je_document_rel_id");

            //复制元数据
            fileMetaDataService.copyFileRelMetadata(userId, oldRelId, newRelId, newPkValue, newFuncCode, newTableCode, newFiledCode);

            //构建DTO
            FileCopyDTO dto = new FileCopyDTO(rel.getName(), rel.getFileKey());
            newCopyFiles.add(dto);
        }
        return newCopyFiles;
    }

    @Override
    @Transactional
    public void deleteFiles(String tableCode, String pkValues, String fieldCOdes, String uploadTypes, String userId) {
        //调用逻辑删除附件
        fileRelService.deleteFilesByPkValues(tableCode, pkValues, fieldCOdes, uploadTypes, userId);
    }

    @Override
    public JSONArray listFilesMeta(String bucket, String path) {
        DocumentBucketDO bucketDO = bucketService.findBucket(bucket);
        Bucket bucketEntity = new Bucket();
        bucketEntity.setBucket(bucketDO.getBucket());
        bucketEntity.setBasePath(bucketDO.getBasePath());
        bucketEntity.setModifiedTime(bucketDO.getModifiedTime());
        bucketEntity.setExt1(bucketDO.getExt1());
        bucketEntity.setExt2(bucketDO.getExt2());
        bucketEntity.setExt3(bucketDO.getExt3());
        bucketEntity.setSaveType(bucketDO.getSaveType());
        bucketEntity.setUrl(bucketDO.getUrl());
        bucketEntity.setPermission(bucketDO.getPermission());
        FileOperateService operate = FileOperateFactory.getInstance(bucketEntity);
        return operate.listFilesMeta(bucket, path);
    }

    @Override
    public void checkFileSuffix(String fileName) {
        List<String> list = new ArrayList<>();
        String suffixs = metaSystemSettingRpcService.requireSettingValue("JE_DOCUMENT_FILE_SUFFIX");
        if (StringUtil.isNotEmpty(suffixs)) {
            list = Arrays.asList(suffixs.split(","));
        }
        if (!DocumentUtil.checkFileSuffix(fileName, list)) {
            throw new DocumentException(MessageUtils.getMessage("document.file.suffix.error", suffixs), DocumentExceptionEnum.DOCUMENT_ERROR);
        }
    }

    @Override
    public String getPreviewOfficeUrl(HttpServletRequest request, String fileKey, String previewType) {
        //获取文件前校验
        checkBeforeGetFile(fileKey);
        DocumentPreviewWayEnum documentPreviewWayEnum = DocumentPreviewWayEnum.no;
        if (Strings.isNullOrEmpty(previewType)) {
            //不包含文件流
            FileBO fileBO = selectFileByKey(fileKey);
            documentPreviewWayEnum = metaSystemSettingRpcService.getDocumentPreviewWayByFileSuffix(fileBO.getSuffix());
        } else {
            if (previewType.equals("pdf")) {
                documentPreviewWayEnum = DocumentPreviewWayEnum.pdf;
            }
        }
        if (documentPreviewWayEnum == DocumentPreviewWayEnum.no) {
            throw new PlatformException(MessageUtils.getMessage("document.file.noSupportPreview"), PlatformExceptionEnum.UNKOWN_ERROR);
        }
        if (documentPreviewWayEnum == DocumentPreviewWayEnum.wps) {
            throw new PlatformException(MessageUtils.getMessage("document.file.preview.noSupportWPS"), PlatformExceptionEnum.UNKOWN_ERROR);
        }
        return OfficePreviewServiceFactory.getOfficePreviewServiceByType(documentPreviewWayEnum).getPreviewUrl(fileKey);
    }

    @Override
    public JSONArray getFileInfo(String fileKeys) {
        if (StringUtil.isEmpty(fileKeys)) {
            return null;
        }

        List<DynaBean> list = metaService.select("JE_DOCUMENT_REL",
                ConditionsWrapper.builder().in("file_key", Arrays.asList(fileKeys.split(",")))
                        .orderByAsc("create_time"));

        if (list == null || list.size() == 0) {
            return null;
        }
        JSONArray jsonArray = new JSONArray();
        for (DynaBean dynaBean : list) {
            JSONObject jsonObject = new JSONObject();
            DynaBean fileinfo = metaService.selectOneByPk("je_document_file", dynaBean.getStr("file_id"));
            jsonObject.put("fileKey", dynaBean.getStr("file_key"));
            jsonObject.put("relName", fileinfo.getStr("full_name"));
            jsonObject.put("suffix", fileinfo.getStr("suffix"));
            jsonObject.put("size", fileinfo.getStr("FILE_SIZE"));
            jsonArray.add(jsonObject);
        }
        return jsonArray;
    }

    @Override
    public boolean existsOnDB(String fileKey) {
        List<DynaBean> relList = metaService.select("je_document_rel",
                ConditionsWrapper.builder().eq("file_key", fileKey));
        if (relList == null || relList.size() == 0) {
            return false;
        }

        for (DynaBean rel : relList) {
            DynaBean dynaBean = metaService.selectOne("je_document_file",
                    ConditionsWrapper.builder().eq("je_document_file_id", rel.getStr("file_id")));
            if (dynaBean != null) {
                return true;
            }
        }
        return false;
    }

    private void checkBeforeGetFile(String fileKey) {
        // 校验文件是否存在
        boolean isExist = exists(fileKey);
        if (!isExist) {
            throw new PlatformException(MessageUtils.getMessage("document.file.not.exist"), PlatformExceptionEnum.UNKOWN_ERROR);
        }
    }

}